import tkinter as tk
from tkinter import ttk
from tkinter import messagebox, filedialog
import os
import json
import datetime
import socket
import threading
import requests
from urllib.parse import urlparse
import time


class MainApp:
    def __init__(self, root):
        self.root = root
        self.load_config()
        self.update_title()
        self.create_main_widgets()
        self.focus_first_scan()
        self.serial_number = 1
        self.current_scan_index = 0
        self.history_records = []
        self.tcp_clients = []
        self.keyboard_modes = [False] * len(self.config["scanners"])
        self.switch_buttons = []
        self.api_enabled = False
        if self.config["mode"] != "keyboard":
            self.start_tcp_connections()

    def get_mode_zh(self):
        mode_zh = {
            "server": "服务器模式",
            "client": "客户端模式",
            "keyboard": "本地模式"
        }
        return mode_zh.get(self.config["mode"], "未知模式")

    def load_config(self):
        config_file = "scan_config.json"
        default_config = {
            "mode": "client",
            "save_path": "D:/条码记录",
            "scanners": [],
            "need_result": True,
            "need_confirm": True,
            "judge_chars": {"1": "OK", "0": "NG"},
            "client_ip": self.get_local_ip(),
            "scan_receive_format": "10进制",
            "result_receive_format": "10进制",
            "force_english": False,
            "api_enabled": False,
            "api_url": "http://127.0.0.1:5000/api/reportApi/report",
            "line_code": "",
            "station_code": ""
        }
        if os.path.exists(config_file):
            try:
                with open(config_file, "r") as f:
                    self.config = json.load(f)
                for key in ["api_enabled", "api_url", "line_code", "station_code"]:
                    if key not in self.config:
                        self.config[key] = default_config[key]
            except Exception as e:
                print(f"加载配置文件出错: {e}")
                self.config = default_config
        else:
            self.config = default_config

    def get_local_ip(self):
        try:
            s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
            s.connect(("8.8.8.8", 80))
            local_ip = s.getsockname()[0]
            s.close()
            return local_ip
        except Exception:
            return "127.0.0.1"

    def save_config(self):
        config_file = "scan_config.json"
        with open(config_file, "w") as f:
            json.dump(self.config, f)

    def create_main_widgets(self):
        self.scan_frame = tk.Frame(self.root)
        self.scan_frame.pack(pady=5)
        self.scan_entries = []
        self.result_entries = []
        self.switch_buttons = []

        num_scanners = len(self.config["scanners"])
        if self.config["need_result"]:
            num_scanners = num_scanners // 2

        for i in range(num_scanners):
            scan_label_text = f"扫码{i + 1}"
            row = i
            tk.Label(self.scan_frame, text=scan_label_text).grid(row=row, column=0)
            entry = tk.Entry(self.scan_frame, width=40)
            entry.grid(row=row, column=1)
            entry.bind("<Return>", lambda e, idx=i: self.handle_scan(idx))
            self.scan_entries.append(entry)

            switch_btn = tk.Button(self.scan_frame, text="键盘", command=lambda idx=i: self.switch_input_mode(idx))
            switch_btn.grid(row=row, column=2)
            self.switch_buttons.append(switch_btn)

            if self.config["need_result"]:
                result_label_text = f"判断{i + 1}"
                tk.Label(self.scan_frame, text=result_label_text).grid(row=row, column=3)
                result_entry = tk.Entry(self.scan_frame, width=10)
                result_entry.grid(row=row, column=4)
                if self.config["need_confirm"]:
                    result_entry.bind("<Return>", lambda e, idx=i: self.handle_result(idx))
                else:
                    result_entry.bind("<KeyRelease>", lambda e, idx=i: self.handle_result(idx))
                self.result_entries.append(result_entry)

        self.history_frame = tk.Frame(self.root)
        self.history_frame.pack(pady=5)
        tk.Label(self.history_frame, text="历史记录:").pack(side=tk.LEFT)
        self.history_text = tk.Text(self.history_frame, width=40, height=10)
        self.history_text.pack(side=tk.LEFT)
        self.history_scroll = tk.Scrollbar(self.history_frame, command=self.history_text.yview)
        self.history_scroll.pack(side=tk.RIGHT, fill=tk.Y)
        self.history_text.configure(yscrollcommand=self.history_scroll.set)

        self.path_frame = tk.Frame(self.root)
        self.path_frame.pack(pady=5)
        tk.Label(self.path_frame, text="保存路径:").pack(side=tk.LEFT)
        self.path_entry = tk.Entry(self.path_frame, width=30)
        self.path_entry.pack(side=tk.LEFT)
        self.path_entry.insert(0, self.config["save_path"])
        tk.Button(self.path_frame, text="选择路径", command=self.choose_save_path).pack(side=tk.LEFT, padx=5)
        tk.Button(self.path_frame, text="打开记录文件夹", command=self.open_save_path).pack(side=tk.LEFT)

        menu_bar = tk.Menu(self.root)
        settings_menu = tk.Menu(menu_bar, tearoff=0)
        settings_menu.add_command(label="系统设置", command=lambda: SettingsApp(self.root, self))
        menu_bar.add_cascade(label="设置", menu=settings_menu)
        self.root.config(menu=menu_bar)

    def focus_first_scan(self):
        if self.scan_entries:
            self.scan_entries[0].focus_set()
            self.current_scan_index = 0

    def handle_scan(self, index):
        self.current_scan_index = index
        if self.config["need_result"]:
            self.result_entries[index].focus_set()
        else:
            scan_code = self.scan_entries[index].get().strip()
            judge_char1 = list(self.config["judge_chars"].keys())[0]
            result_text = self.config["judge_chars"].get(judge_char1)
            self.save_record(scan_code, result_text)
            if self.config["api_enabled"]:
                threading.Thread(target=self.send_api_request, args=(scan_code, result_text)).start()
            self.focus_next_scan(index)

    def handle_result(self, index):
        result_char = self.result_entries[index].get().strip()
        scan_code = self.scan_entries[index].get().strip()
        now = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        result_text = self.config["judge_chars"].get(result_char, "未知结果")

        if result_char in self.config["judge_chars"]:
            if self.config["need_confirm"]:
                self.save_record(scan_code, result_text)
                self.reset_inputs()
                if self.config["api_enabled"]:
                    threading.Thread(target=self.send_api_request, args=(scan_code, result_text)).start()
                self.focus_next_scan(index)
            else:
                self.save_record(scan_code, result_text)
                if self.config["api_enabled"]:
                    threading.Thread(target=self.send_api_request, args=(scan_code, result_text)).start()
                self.focus_next_scan(index)

    def save_record(self, barcode, result):
        now = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        record = f"{now} - 条码: {barcode}, 结果: {result}"
        self.history_records.append(record)
        if len(self.history_records) > 10:
            self.history_records.pop(0)
        self.history_text.delete("1.0", tk.END)
        for rec in self.history_records:
            self.history_text.insert(tk.END, rec + "\n")
        self.history_text.see(tk.END)
        self.save_to_csv(barcode, result)
        self.reset_inputs()

    def auto_save(self, index):
        scan_code = self.scan_entries[index].get().strip()
        judge_char1 = list(self.config["judge_chars"].keys())[0]
        result_text = self.config["judge_chars"].get(judge_char1)
        self.save_record(scan_code, result_text)

    def focus_next_scan(self, current_index):
        next_index = current_index + 1
        if next_index < len(self.scan_entries):
            self.scan_entries[next_index].focus_set()
            self.current_scan_index = next_index
        else:
            self.scan_entries[0].focus_set()
            self.current_scan_index = 0

    def reset_inputs(self):
        for entry in self.scan_entries:
            entry.delete(0, tk.END)
        if self.config["need_result"]:
            for entry in self.result_entries:
                entry.delete(0, tk.END)

    def save_to_csv(self, barcode, result):
        save_base = self.path_entry.get()
        if not save_base:
            messagebox.showerror("错误", "请先设置保存路径")
            return

        now = datetime.datetime.now()
        year_dir = now.strftime("%Y")
        month_dir = now.strftime("%m")
        date_str = now.strftime("%y%m%d")
        save_path = os.path.join(save_base, year_dir, month_dir)
        os.makedirs(save_path, exist_ok=True)

        file_name = f"{date_str}.csv"
        file_path = os.path.join(save_path, file_name)

        is_new_file = not os.path.exists(file_path)
        with open(file_path, "a", encoding="utf-8-sig") as f:
            if is_new_file:
                headers = "序号,时间,条码"
                if self.config["need_result"]:
                    headers += ",判断结果"
                f.write(headers + "\n")
            row = f"{self.serial_number},{now.strftime('%Y-%m-%d %H:%M:%S')},{barcode}"
            if self.config["need_result"]:
                row += f",{result}"
            f.write(row + "\n")
            self.serial_number += 1

    def choose_save_path(self):
        path = filedialog.askdirectory()
        if path:
            self.path_entry.delete(0, tk.END)
            self.path_entry.insert(0, path)
            self.config["save_path"] = path
            self.save_config()

    def open_save_path(self):
        path = self.path_entry.get()
        if os.path.exists(path):
            os.startfile(path)
        else:
            messagebox.showerror("错误", "路径不存在")

    def start_tcp_connections(self):
        for i, scanner in enumerate(self.config["scanners"]):
            ip = scanner.get("ip")
            port = scanner.get("port", 8888)
            if ip:
                try:
                    client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
                    client.connect((ip, port))
                    self.tcp_clients.append(client)
                    thread = threading.Thread(target=self.receive_data, args=(client, i))
                    thread.daemon = True
                    thread.start()
                except Exception as e:
                    messagebox.showerror("错误", f"连接扫码枪 {ip}:{port} 失败: {e}")

    def receive_data(self, client, index):
        try:
            while True:
                data = client.recv(1024)
                if not data:
                    break
                if index % 2 == 0:
                    if self.config["scan_receive_format"] == "16进制":
                        barcode = data.hex()
                    else:
                        barcode = data.decode('utf-8').strip()
                else:
                    if self.config["result_receive_format"] == "16进制":
                        barcode = data.hex()
                    else:
                        barcode = data.decode('utf-8').strip()
                self.root.after(0, lambda: self.handle_tcp_scan(barcode, index))
        except Exception as e:
            messagebox.showerror("错误", f"接收扫码枪数据失败: {e}")
            self.tcp_clients[index] = None
            if self.config["mode"] in ["server", "client"]:
                threading.Thread(target=self.reconnect, args=(index,)).start()
        finally:
            if client:
                client.close()

    def reconnect(self, index):
        time.sleep(5)
        scanner = self.config["scanners"][index]
        ip = scanner.get("ip")
        port = scanner.get("port", 8888)
        if ip:
            try:
                client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
                client.connect((ip, port))
                self.tcp_clients[index] = client
                thread = threading.Thread(target=self.receive_data, args=(client, index))
                thread.daemon = True
                thread.start()
            except Exception as e:
                messagebox.showerror("错误", f"重新连接扫码枪 {ip}:{port} 失败: {e}")

    def handle_tcp_scan(self, barcode, index):
        if self.config["force_english"]:
            barcode = barcode.encode('ascii', 'ignore').decode('ascii')
        scan_index = index // 2
        if scan_index < len(self.scan_entries):
            if self.keyboard_modes[scan_index]:
                return
            if index % 2 == 0:
                self.scan_entries[scan_index].delete(0, tk.END)
                self.scan_entries[scan_index].insert(0, barcode)
                if self.config["need_result"]:
                    self.result_entries[scan_index].focus_set()
                else:
                    judge_char1 = list(self.config["judge_chars"].keys())[0]
                    result_text = self.config["judge_chars"].get(judge_char1)
                    scan_code = barcode
                    self.save_record(scan_code, result_text)
                    if self.config["api_enabled"]:
                        threading.Thread(target=self.send_api_request, args=(scan_code, result_text)).start()
                    self.focus_next_scan(scan_index)
            else:
                result_char = barcode
                result_text = self.config["judge_chars"].get(result_char, "未知结果")
                self.result_entries[scan_index].delete(0, tk.END)
                self.result_entries[scan_index].insert(0, result_char)
                if result_char in self.config["judge_chars"]:
                    if self.config["need_confirm"]:
                        scan_code = self.scan_entries[scan_index].get().strip()
                        self.save_record(scan_code, result_text)
                        if self.config["api_enabled"]:
                            threading.Thread(target=self.send_api_request, args=(scan_code, result_text)).start()
                        self.reset_inputs()
                        self.focus_next_scan(scan_index)
                    else:
                        scan_code = self.scan_entries[scan_index].get().strip()
                        self.save_record(scan_code, result_text)
                        if self.config["api_enabled"]:
                            threading.Thread(target=self.send_api_request, args=(scan_code, result_text)).start()
                        self.focus_next_scan(scan_index)

    def switch_input_mode(self, index):
        self.keyboard_modes[index] = not self.keyboard_modes[index]
        if self.keyboard_modes[index]:
            self.switch_buttons[index].config(text="扫码")
        else:
            self.switch_buttons[index].config(text="键盘")

    def send_api_request(self, barcode, result):
        url = self.config["api_url"]
        line_code = self.config["line_code"]
        station_code = self.config["station_code"]

        if not self.validate_url(url):
            self.update_result("错误: 无效的API URL格式")
            return

        if not line_code or not station_code:
            self.update_result("错误: 请先配置产线编号和工位编号")
            return

        data = {
            "lineCode": line_code,
            "stationCode": station_code,
            "sn": barcode,
            "qty": 1,
            "result": result
        }

        try:
            response = requests.post(url, json=data, timeout=10)
            self.handle_api_response(response, barcode)
        except requests.exceptions.Timeout:
            self.update_result(f"错误: 请求超时，SN: {barcode}")
        except requests.exceptions.ConnectionError:
            self.update_result(f"错误: 无法连接到服务器，SN: {barcode}")
        except Exception as e:
            self.update_result(f"意外错误，SN: {barcode}: {str(e)}")

    def handle_api_response(self, response, sn):
        try:
            if response.status_code == 200:
                self.update_result(f"API请求成功，SN: {sn}")
            else:
                self.update_result(f"API请求失败，状态码: {response.status_code}，SN: {sn}")
        except Exception as e:
            self.update_result(f"响应处理错误，SN: {sn}: {str(e)}")

    def validate_url(self, url):
        try:
            result = urlparse(url)
            return all([result.scheme in ('http', 'https'), result.netloc])
        except:
            return False

    def update_result(self, message):
        self.root.after(0, lambda: self._update_result(message))

    def _update_result(self, message):
        self.history_text.insert(tk.END, f"\n{message}")
        self.history_text.see(tk.END)

    def update_title(self):
        line_code = self.config["line_code"]
        station_code = self.config["station_code"]
        mode_zh = self.get_mode_zh()
        title = f"{line_code}-{station_code} 扫码系统 - {mode_zh}"
        self.root.title(title)


class SettingsApp:
    def __init__(self, root, main_app):
        self.root = root
        self.main_app = main_app
        self.settings_window = tk.Toplevel(root)
        self.settings_window.title("系统设置")
        self.entry_order = []
        self.settings_window.geometry("600x500")

        main_frame = tk.Frame(self.settings_window)
        main_frame.pack(padx=10, pady=10, fill=tk.BOTH, expand=True)

        self.scroll_frame = tk.Frame(main_frame)
        self.scroll_frame.pack(fill=tk.BOTH, expand=True)

        self.canvas = tk.Canvas(self.scroll_frame)
        self.scrollbar = ttk.Scrollbar(self.scroll_frame, orient="vertical", command=self.canvas.yview)
        self.scrollable_frame = ttk.Frame(self.canvas)

        self.scrollable_frame.bind(
            "<Configure>",
            lambda e: self.canvas.configure(
                scrollregion=self.canvas.bbox("all")
            )
        )

        self.canvas.create_window((0, 0), window=self.scrollable_frame, anchor="nw")
        self.canvas.configure(yscrollcommand=self.scrollbar.set)

        self.canvas.pack(side="left", fill="both", expand=True)
        self.scrollbar.pack(side="right", fill="y")

        self.create_settings_content()

    def create_settings_content(self):
        self.button_frame = tk.Frame(self.scrollable_frame)

        tk.Label(self.scrollable_frame, text="运行模式:").grid(row=0, column=0, sticky='w')
        mode_frame = tk.Frame(self.scrollable_frame)
        mode_frame.grid(row=0, column=1, columnspan=3, sticky='ew')

        self.scrollable_frame.grid_columnconfigure(1, weight=1)
        self.scrollable_frame.grid_columnconfigure(2, weight=1)
        self.scrollable_frame.grid_columnconfigure(3, weight=1)

        self.mode_var = tk.StringVar(master=self.settings_window)
        self.mode_var.set(self.main_app.config["mode"])

        tk.Radiobutton(mode_frame, text="服务器模式", variable=self.mode_var, value="server").pack(side=tk.LEFT, expand=True, fill=tk.X, padx=5)
        tk.Radiobutton(mode_frame, text="客户端模式", variable=self.mode_var, value="client").pack(side=tk.LEFT, expand=True, fill=tk.X, padx=5)
        tk.Radiobutton(mode_frame, text="本地模式", variable=self.mode_var, value="keyboard").pack(side=tk.LEFT, expand=True, fill=tk.X, padx=5)

        self.mode_var.trace_add("write", self.update_client_ip_visibility)

        self.client_ip_label = tk.Label(self.scrollable_frame, text="本机 IP:")
        self.client_ip_entry = tk.Entry(self.scrollable_frame, width=20)
        self.client_ip_entry.insert(0, self.main_app.config["client_ip"])
        self.client_ip_entry.bind("<Return>", lambda e, entry=self.client_ip_entry: self.focus_next(entry))
        self.entry_order.append(self.client_ip_entry)

        self.update_client_ip_visibility()

        tk.Label(self.scrollable_frame, text="API设置:").grid(row=2, column=0, pady=10)

        tk.Label(self.scrollable_frame, text="请求URL:").grid(row=3, column=0)
        self.api_url_entry = tk.Entry(self.scrollable_frame, width=40)
        self.api_url_entry.insert(0, self.main_app.config["api_url"])
        self.api_url_entry.bind("<Return>", lambda e, entry=self.api_url_entry: self.focus_next(entry))
        self.entry_order.append(self.api_url_entry)
        self.api_url_entry.grid(row=3, column=1)

        tk.Label(self.scrollable_frame, text="产线编号:").grid(row=4, column=0)
        self.line_code_entry = tk.Entry(self.scrollable_frame, width=20)
        self.line_code_entry.insert(0, self.main_app.config["line_code"])
        self.line_code_entry.bind("<Return>", lambda e, entry=self.line_code_entry: self.focus_next(entry))
        self.entry_order.append(self.line_code_entry)
        self.line_code_entry.grid(row=4, column=1)

        tk.Label(self.scrollable_frame, text="工位编号:").grid(row=5, column=0)
        self.station_code_entry = tk.Entry(self.scrollable_frame, width=20)
        self.station_code_entry.insert(0, self.main_app.config["station_code"])
        self.station_code_entry.bind("<Return>", lambda e, entry=self.station_code_entry: self.focus_next(entry))
        self.entry_order.append(self.station_code_entry)
        self.station_code_entry.grid(row=5, column=1)

        self.api_enabled_var = tk.BooleanVar(master=self.settings_window)
        self.api_enabled_var.set(self.main_app.config["api_enabled"])
        tk.Checkbutton(self.scrollable_frame, text="启用API发送", variable=self.api_enabled_var).grid(row=6, column=0)

        self.need_result_var = tk.BooleanVar(master=self.settings_window)
        self.need_result_var.set(self.main_app.config["need_result"])
        self.need_result_checkbox = tk.Checkbutton(self.scrollable_frame, text="需要判断结果", variable=self.need_result_var,
                                                   command=self.update_need_result)
        self.need_result_checkbox.grid(row=7, column=0)

        self.need_confirm_var = tk.BooleanVar(master=self.settings_window)
        self.need_confirm_var.set(self.main_app.config["need_confirm"])
        tk.Checkbutton(self.scrollable_frame, text="需要判断确认", variable=self.need_confirm_var).grid(row=7, column=1)

        tk.Label(self.scrollable_frame, text="判断字符1:").grid(row=8, column=0)
        self.judge_char1 = tk.Entry(self.scrollable_frame, width=10)
        self.judge_char1.insert(0, list(self.main_app.config["judge_chars"].keys())[0])
        self.judge_char1.bind("<Return>", lambda e, entry=self.judge_char1: self.focus_next(entry))
        self.entry_order.append(self.judge_char1)
        self.judge_char1.grid(row=8, column=1)

        tk.Label(self.scrollable_frame, text="判断结果1:").grid(row=8, column=2)
        self.judge_result1 = tk.Entry(self.scrollable_frame, width=10)
        self.judge_result1.insert(0, list(self.main_app.config["judge_chars"].values())[0])
        self.judge_result1.bind("<Return>", lambda e, entry=self.judge_result1: self.focus_next(entry))
        self.entry_order.append(self.judge_result1)
        self.judge_result1.grid(row=8, column=3)

        tk.Label(self.scrollable_frame, text="判断字符2:").grid(row=9, column=0)
        self.judge_char2 = tk.Entry(self.scrollable_frame, width=10)
        self.judge_char2.insert(0, list(self.main_app.config["judge_chars"].keys())[1])
        self.judge_char2.bind("<Return>", lambda e, entry=self.judge_char2: self.focus_next(entry))
        self.entry_order.append(self.judge_char2)
        self.judge_char2.grid(row=9, column=1)

        tk.Label(self.scrollable_frame, text="判断结果2:").grid(row=9, column=2)
        self.judge_result2 = tk.Entry(self.scrollable_frame, width=10)
        self.judge_result2.insert(0, list(self.main_app.config["judge_chars"].values())[1])
        self.judge_result2.bind("<Return>", lambda e, entry=self.judge_result2: self.focus_next(entry))
        self.entry_order.append(self.judge_result2)
        self.judge_result2.grid(row=9, column=3)

        tk.Label(self.scrollable_frame, text="扫码接收格式:").grid(row=10, column=0)
        self.scan_receive_format_var = tk.StringVar(master=self.settings_window)
        self.scan_receive_format_var.set(self.main_app.config["scan_receive_format"])
        tk.Radiobutton(self.scrollable_frame, text="10进制", variable=self.scan_receive_format_var, value="10进制").grid(row=10, column=1)
        tk.Radiobutton(self.scrollable_frame, text="16进制", variable=self.scan_receive_format_var, value="16进制").grid(row=10, column=2)

        tk.Label(self.scrollable_frame, text="判断接收格式:").grid(row=11, column=0)
        self.result_receive_format_var = tk.StringVar(master=self.settings_window)
        self.result_receive_format_var.set(self.main_app.config["result_receive_format"])
        tk.Radiobutton(self.scrollable_frame, text="10进制", variable=self.result_receive_format_var, value="10进制").grid(row=11, column=1)
        tk.Radiobutton(self.scrollable_frame, text="16进制", variable=self.result_receive_format_var, value="16进制").grid(row=11, column=2)

        self.force_english_var = tk.BooleanVar(master=self.settings_window)
        self.force_english_var.set(self.main_app.config["force_english"])
        tk.Checkbutton(self.scrollable_frame, text="强制英文状态", variable=self.force_english_var).grid(row=12, column=0)

        self.scanner_frame = tk.Frame(self.scrollable_frame)
        self.scanner_frame.grid(row=13, column=0, columnspan=4, pady=10)
        self.scanner_entries = []
        for i, scanner in enumerate(self.main_app.config["scanners"]):
            self.add_scanner_row(i, scanner)

        self.update_button_position()

    def update_client_ip_visibility(self, *args):
        if self.mode_var.get() == "client":
            self.client_ip_label.grid(row=1, column=0)
            self.client_ip_entry.grid(row=1, column=1)
        else:
            self.client_ip_label.grid_forget()
            self.client_ip_entry.grid_forget()

    def add_scanner_row(self, index, scanner):
        var = tk.IntVar()
        if self.need_result_var.get():
            scan_num = (index // 2) + 1
            if index % 2 == 0:
                checkbutton_text = f"扫码枪{scan_num}"
            else:
                checkbutton_text = f"扫码枪{scan_num}.1"
        else:
            checkbutton_text = f"扫码枪{index + 1}"
        checkbutton = tk.Checkbutton(self.scanner_frame, variable=var, text=checkbutton_text)
        checkbutton.grid(row=index, column=0)
        ip_entry = tk.Entry(self.scanner_frame, width=20)
        ip_entry.insert(0, scanner.get("ip", ""))
        ip_entry.bind("<Return>", lambda e, entry=ip_entry: self.focus_next(entry))
        self.entry_order.append(ip_entry)
        ip_entry.grid(row=index, column=1)

        tk.Label(self.scanner_frame, text="端口号:").grid(row=index, column=2)
        port_entry = tk.Entry(self.scanner_frame, width=10)
        port_entry.insert(0, str(scanner.get("port", 8888)))
        port_entry.bind("<Return>", lambda e, entry=port_entry: self.focus_next(entry))
        self.entry_order.append(port_entry)
        port_entry.grid(row=index, column=3)

        self.scanner_entries.append((var, ip_entry, port_entry))
        self.update_button_position()

    def remove_scanner(self):
        if self.scanner_entries:
            var, ip_entry, port_entry = self.scanner_entries.pop()
            var.set(0)
            ip_entry.destroy()
            port_entry.destroy()
            self.entry_order = [e for e in self.entry_order if e not in (ip_entry, port_entry)]
            self.update_button_position()

    def update_button_position(self):
        if hasattr(self, 'button_frame'):
            self.button_frame.destroy()

        self.button_frame = tk.Frame(self.scrollable_frame)
        self.button_frame.grid(row=13 + len(self.scanner_entries) + 1, column=0, columnspan=4, pady=10)

        self.add_btn = tk.Button(self.button_frame, text="添加扫码枪", command=self.add_scanner)
        self.remove_btn = tk.Button(self.button_frame, text="移除扫码枪", command=self.remove_scanner)
        self.save_btn = tk.Button(self.button_frame, text="保存设置", command=self.save_settings)

        self.add_btn.pack(side=tk.LEFT, padx=5)
        self.remove_btn.pack(side=tk.LEFT, padx=5)
        self.save_btn.pack(side=tk.LEFT, padx=5)

    def add_scanner(self):
        row = len(self.scanner_entries)
        self.add_scanner_row(row, {"ip": "", "port": 8888})
        self.update_button_position()

    def save_settings(self):
        self.main_app.config["mode"] = self.mode_var.get()
        self.main_app.config["need_result"] = self.need_result_var.get()
        self.main_app.config["need_confirm"] = self.need_confirm_var.get()
        self.main_app.config["judge_chars"] = {
            self.judge_char1.get(): self.judge_result1.get(),
            self.judge_char2.get(): self.judge_result2.get()
        }

        scanners = []
        for var, ip_entry, port_entry in self.scanner_entries:
            if var.get() == 1:
                ip = ip_entry.get().strip()
                port = port_entry.get().strip()
                if ip:
                    scanners.append({
                        "ip": ip,
                        "port": int(port) if port else 8888
                    })
        self.main_app.config["scanners"] = scanners

        if self.mode_var.get() == "client":
            self.main_app.config["client_ip"] = self.client_ip_entry.get().strip()

        self.main_app.config["scan_receive_format"] = self.scan_receive_format_var.get()
        self.main_app.config["result_receive_format"] = self.result_receive_format_var.get()
        self.main_app.config["force_english"] = self.force_english_var.get()

        self.main_app.config["api_enabled"] = self.api_enabled_var.get()
        self.main_app.config["api_url"] = self.api_url_entry.get().strip()
        self.main_app.config["line_code"] = self.line_code_entry.get().strip()
        self.main_app.config["station_code"] = self.station_code_entry.get().strip()

        self.main_app.save_config()
        self.main_app.update_title()
        self.settings_window.destroy()

    def focus_next(self, entry):
        current_index = self.entry_order.index(entry)
        next_index = (current_index + 1) % len(self.entry_order)
        self.entry_order[next_index].focus_set()

    def update_need_result(self):
        need_result = self.need_result_var.get()
        for i, (var, ip_entry, port_entry) in enumerate(self.scanner_entries):
            if need_result:
                scan_num = (i // 2) + 1
                if i % 2 == 0:
                    var.set(1)
                    ip_entry.config(state=tk.NORMAL)
                    port_entry.config(state=tk.NORMAL)
                    checkbutton_text = f"扫码枪{scan_num}"
                else:
                    var.set(1)
                    ip_entry.config(state=tk.NORMAL)
                    port_entry.config(state=tk.NORMAL)
                    checkbutton_text = f"扫码枪{scan_num}.1"
            else:
                var.set(1)
                ip_entry.config(state=tk.NORMAL)
                port_entry.config(state=tk.NORMAL)


if __name__ == "__main__":
    root = tk.Tk()
    app = MainApp(root)
    root.mainloop()
